home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / HippoDraw / hippo / hippoplot.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-28  |  56.9 KB  |  2,627 lines

  1. /*
  2.  * hippoplot.c - Routines for displaying hippo ntuples.
  3.  *
  4.  * Copyright (C)  1991  The Board of Trustees of The Leland Stanford
  5.  * Junior University.  All Rights Reserved.
  6.  *
  7.  * $Id: hippoplot.c,v 3.20 1992/04/24 01:12:19 rensing Rel $
  8.  *
  9.  * by jonas karlsson, at SLAC, August 1990
  10.  *  split up by Paul Rensing, Feb 28,1991
  11.  *  modified by M. Gravina, March 28, 1991
  12.  */
  13.  
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <math.h>
  17. #include <string.h>
  18. #include <float.h>
  19. #include <ctype.h>
  20. #include "hippo.h"
  21. #include "hippoutil.h"
  22.  
  23. GLOB_QUAL const char hippoplot_c_rcsid[] = 
  24.      "$Id: hippoplot.c,v 3.20 1992/04/24 01:12:19 rensing Rel $";
  25.  
  26.  
  27. #ifdef _NEXT_PLOT_
  28. #include "hippoplotNeXT.h"
  29. #ifndef DEF_PLOT_DRVR
  30. #define DEF_PLOT_DRVR NEXT
  31. #endif
  32. #endif
  33.  
  34. #ifdef _UNIXPLOT_PLOT_
  35. #include "hippoplotUP.h"
  36. #ifndef DEF_PLOT_DRVR
  37. #define DEF_PLOT_DRVR UNIXPLOT
  38. #endif
  39. #endif
  40.  
  41. #ifdef _XIV_PLOT_
  42. #include "hippoplotXIV.h"
  43. #ifndef DEF_PLOT_DRVR
  44. #define DEF_PLOT_DRVR XIVPLOT
  45. #endif
  46. #endif
  47.  
  48. #ifdef _X11_PLOT_
  49. #include "hippoplotX11.h"
  50. #ifndef DEF_PLOT_DRVR
  51. #define DEF_PLOT_DRVR X11PLOT
  52. #endif
  53. #endif
  54.  
  55. #ifdef THINK_C
  56. #include "hippoplotMAC.h"
  57. #ifndef DEF_PLOT_DRVR
  58. #define DEF_PLOT_DRVR MAC
  59. #endif
  60. #endif
  61.  
  62. #include "hippoplotPS.h"
  63. #ifndef DEF_PLOT_DRVR
  64. #define DEF_PLOT_DRVR PSPLOT
  65. #endif
  66.  
  67. #define NUM_FUZZ FLT_EPSILON*4
  68.  
  69. /* find offset to matrix element */
  70. #define INDEX(row, column, totcols) ((row) * (totcols) + (column))
  71. #define BININDEX(x, y, z, xs, ys) ((xs) * (ys) * (z) + (x) * (ys) + y)
  72.  
  73. #define MIN(x, y)  (((x) > (y)) ? (y) : (x))
  74. #define MAX(x, y)  (((x) > (y)) ? (x) : (y))
  75.  
  76. #define XPADDING(disp) ((disp)->drawRect.size.width*0.01)
  77. #define YPADDING(disp) ((disp)->drawRect.size.height*0.01)
  78.  
  79.  
  80. #ifdef VMS
  81. #define Concat3(x,y,z) x/**/y/**/z
  82. #else
  83. #define Concat3(x,y,z) x##y##z
  84. #endif
  85.  
  86. #ifdef _NEXT_PLOT_
  87. #define NeXTFunc(name,parm)           \
  88. case NEXT:                            \
  89.      rc = Concat3(name,_NeXT,parm);   \
  90.      break;
  91.  
  92. #else
  93. #define NeXTFunc(name,parm)  
  94. #endif
  95.  
  96. #ifdef _UNIXPLOT_PLOT_
  97. #define UPFunc(name,parm)           \
  98. case UNIXPLOT:                      \
  99.      rc = Concat3(name,_UP,parm);   \
  100.      break;
  101.  
  102. #else
  103. #define UPFunc(name,parm)  
  104. #endif
  105.  
  106. #ifdef _XIV_PLOT_
  107. #define XIVFunc(name,parm)         \
  108. case XIVPLOT:                      \
  109.      Concat3(name,_XIV,parm);      \
  110.      rc = 0;                       \
  111.      break;
  112.  
  113. #else
  114. #define XIVFunc(name,parm)  
  115. #endif
  116.  
  117. #ifdef _X11_PLOT_
  118. #define X11Func(name,parm)           \
  119. case X11PLOT:                        \
  120.      Concat3(name,_X11,parm);        \
  121.      rc = 0;                         \
  122.      break;
  123.  
  124. #else
  125. #define X11Func(name,parm)  
  126. #endif
  127.  
  128. #ifdef THINK_C
  129. #define MACFunc(name,parm)           \
  130. case MAC:                            \
  131.      Concat3(name,_MAC,parm);        \
  132.      rc = 0;                         \
  133.      break;
  134.  
  135. #else
  136. #define MACFunc(name,parm)  
  137. #endif
  138.  
  139. /*
  140.  * always make PS driver available
  141.  */
  142. #define PSFunc(name,parm)           \
  143. case PSPLOT:                        \
  144. case EPSPLOT:                       \
  145.      Concat3(name,_PS,parm);        \
  146.      rc = 0;                        \
  147.      break;
  148.  
  149. #define PlotSwitch(drvr,name, parm) \
  150. switch (drvr)                       \
  151. {                                   \
  152.      NeXTFunc(name,parm)            \
  153.      UPFunc(name,parm)              \
  154.      XIVFunc(name,parm)             \
  155.      X11Func(name,parm)             \
  156.      MACFunc(name,parm)             \
  157.      PSFunc(name,parm)              \
  158.      default:                       \
  159.       rc = -1;                  \
  160. }
  161.  
  162. struct maxs 
  163. {
  164.      float xl,xh,yl,yh;
  165. };
  166.  
  167.  
  168. /* 
  169.  * private functions
  170.  */
  171. static float calcTicks(float size, float *magnitude);
  172.  
  173. static int drawData( display disp );
  174. static int drawData1D( display disp );
  175. static int drawAxis( display disp );
  176. static int drawLabels( display disp );
  177.  
  178. static int drawLego1D(display disp, float *lego, int *over, int npts);
  179. static int drawPoint1D(display disp, float *xy, int *over, int npts);
  180. static int drawError1D(display disp, float *xy, float *err, 
  181.                int *over, int npts, int err_type);
  182. static int drawLine1D(display disp, float *xy, int *over, 
  183.               int npts, int xmin_pt, linestyle_t ls);
  184. static void box_cross(float *p1, float *p2, display disp);
  185. int intcmp(const void *i1, const void *i2);
  186.  
  187. static int drawColor2D(display disp);
  188. static int drawScatter2D(display disp);
  189. static int drawLego2D(display disp);
  190.  
  191. static int initPlot(display disp);
  192. static int endPlot(display disp);
  193. static int drawAxisBox( display disp );
  194. static int drawTicks(display disp, binding_t axis);
  195. static int drawXTicks(float *ticks, int nticks, float tickLength, char tickLoc );
  196. static int drawYTicks(float *ticks, int nticks, float tickLength, char tickLoc );
  197. static int drawMag( float x, float y, int mag, float fontSize );
  198.  
  199. static int drawText(char *s, float x, float y, float fontsize, float angle,
  200.             char xp, char yp );
  201.  
  202. static int getXYData( display disp, float **xy, float **xerr, 
  203.     float **yerr, int **over, struct maxs *m, int *xmin_pt);
  204. static int getHistoData( display disp, float **xy, float **xylego, 
  205.     float **xerr, float **yerr, int **over,struct maxs *m);
  206. static int getScatData( display disp, float **xy, struct maxs *m );
  207.  
  208. static int plotFunc(display disp, func_id fun );
  209.  
  210. /*
  211.  * global variables.
  212.  */
  213. static int init_done;
  214. static plotdrvr_t plot_drvr = DEF_PLOT_DRVR;
  215.  
  216. #ifdef _XIV_PLOT_
  217. /* For passing to the X Interviews driver... */
  218. static void* canvas;
  219. static void* painter;
  220. #endif
  221.  
  222. #ifdef _X11_PLOT_
  223. /* for passing to X11 driver ... */
  224. static void* dpy;
  225. static void* screen;
  226. static void* drawable;
  227. static void* gc;
  228. #endif
  229.  
  230.  
  231. int h_setPlotDrvr( plotdrvr_t drvr, ...)
  232. {
  233.      int rc;
  234.      va_list argPtr;
  235.      void *parm;
  236.      
  237.      switch (drvr)
  238.      {
  239. #ifdef _NEXT_PLOT_
  240.      case NEXT:
  241. #endif
  242. #ifdef _XIV_PLOT_
  243.      case XIVPLOT:
  244. #endif      
  245. #ifdef _X11_PLOT_
  246.      case X11PLOT:
  247. #endif      
  248. #ifdef THINK_C
  249.      case MAC:
  250. #endif
  251.      case LPR:
  252.       rc = 0;
  253.       break;
  254.             
  255.      case PSPLOT:
  256.      case EPSPLOT:
  257.       va_start( argPtr, drvr );
  258.       parm = va_arg(argPtr, FILE *);
  259.       rc = initDrvr_PS( parm );
  260.       va_end(argPtr);
  261.       break;
  262.  
  263. #ifdef _UNIXPLOT_PLOT_
  264.      case UNIXPLOT:
  265.       va_start( argPtr, drvr );
  266.       parm = va_arg(argPtr, FILE *); /* this shit does not work yet */
  267.       rc = initDrvr_UP( parm );
  268.       va_end(argPtr);
  269.       break;
  270. #endif
  271.             
  272.      default:
  273.       h_error("h_setPlotDrvr - invalid plot driver. Driver may not be compiled in this version.\n");
  274.       rc = -1;
  275.      }
  276.      
  277.      if (rc == 0) 
  278.       plot_drvr = drvr;
  279.      else
  280.       h_error("h_setPlotDrvr - error in driver init. Driver not changed.\n");
  281.      
  282.      return rc;
  283. }
  284.  
  285. int h_endPlotDrvr( void )
  286. {
  287.      int rc;
  288.      
  289.      switch (plot_drvr)
  290.      {
  291.      case PSPLOT:
  292.      case EPSPLOT:
  293.       rc = endDrvr_PS( );
  294.       break;
  295.  
  296.      default:
  297.       rc = 0;
  298.      }
  299.      
  300.      return rc;
  301. }
  302.  
  303. int h_endPage( void )
  304. {
  305.      int rc;
  306.      
  307.      switch (plot_drvr)
  308.      {
  309.      case PSPLOT:
  310.      case EPSPLOT:
  311.       rc = endPage_PS( );
  312.       break;
  313.  
  314.      default:
  315.       rc = 0;
  316.      }
  317.      
  318.      return rc;
  319. }
  320.  
  321. int h_plot(display disp,...)
  322.      int rc = 0;
  323.      func_id fun;
  324. #if defined(_XIV_PLOT_) || defined(_X11_PLOT_)
  325.      va_list argPtr;
  326. #endif
  327.      
  328.      /* 
  329.       * be nice. If driver is lineprinter, call h_print.
  330.       */
  331.      if (plot_drvr == LPR)
  332.      {
  333.       h_print( disp );
  334.       return 0;
  335.      }
  336.      
  337. #ifdef _XIV_PLOT_
  338.      if (plot_drvr == XIVPLOT)
  339.      {
  340.       va_start( argPtr, disp );
  341.       painter = va_arg(argPtr, void *);
  342.       canvas  = va_arg(argPtr, void *);
  343.       va_end(argPtr);
  344.      }
  345. #endif
  346.  
  347. #ifdef _X11_PLOT_
  348.      if (plot_drvr == X11PLOT)
  349.      {
  350.       va_start( argPtr, disp );
  351.       dpy       = va_arg(argPtr, void *);
  352.       screen    = va_arg(argPtr, void *);
  353.       drawable  = va_arg(argPtr, void *);
  354.       gc        = va_arg(argPtr, void *);
  355.       va_end(argPtr);
  356.      }
  357. #endif
  358.  
  359.      if (h_bin(disp) != 0) return -1;
  360.      
  361.      init_done = 0;
  362.           
  363.      drawData(disp);
  364.      
  365.      for (fun = disp->plot_func; fun != NULL && rc == 0; fun = fun->next )
  366.      {
  367.       rc = plotFunc( disp, fun );
  368.      }
  369.  
  370.      if (disp->flags.drawAxes) drawAxis(disp);    
  371.      
  372.      if (disp->flags.drawTitles) drawLabels( disp );
  373.      
  374.      endPlot( disp );
  375.      
  376.      return 0;
  377. }
  378.  
  379.  
  380. #define LABEL_SPACE_X    4.0
  381. #define LABEL_SPACE_Y    4.0
  382. #define MIN_TICKS 4
  383. #define MAX_TICKS (MIN_TICKS*2+1)
  384.  
  385. static float calcTicks(float size, float *magnitude)
  386. {
  387.      static float    goodTicks[] = {10.0, 5.0, 4.0, 2.0, 1.0};
  388.      float        tickSize;
  389.      int        tickIndex;
  390.  
  391.      if (size <= 0.0) 
  392.      {
  393.       h_error("calcTicks: size is <= 0");
  394.       size = fabs(size);
  395.       if (size == 0.0) size = 1.0;
  396.      }
  397.      
  398.      *magnitude = floor(log10(size));
  399.      if (size/pow(10.0,*magnitude) < MIN_TICKS) (*magnitude)--;
  400.  
  401.      /*
  402.       *  now fit the max number of ticks into this range
  403.       */
  404.      for (tickIndex = 0;
  405.       size / (tickSize=goodTicks[tickIndex]*pow(10.0,*magnitude) ) 
  406.       < MIN_TICKS;
  407.       tickIndex++);
  408.  
  409.      if (tickIndex == 0) 
  410.       (*magnitude)++;
  411.      
  412.      return tickSize;
  413. }
  414.  
  415. static int drawAxis(display disp)
  416. {
  417.      if (disp == NULL) return -1;
  418.      
  419.      if (disp->graphtype == LEGOPLOT && disp->dim == 2) return 0;
  420.      
  421.      if (!init_done)
  422.      {
  423.       initPlot(disp);
  424.       init_done = 1;
  425.      }
  426.      
  427.      drawAxisBox( disp );
  428.      if (drawTicks(disp,YAXIS))
  429.       h_error("drawAxis: error drawing y ticks");
  430.      if (drawTicks(disp,XAXIS)) 
  431.       h_error("drawAxis: error drawing x ticks");
  432.  
  433.      return 0;
  434. }
  435.  
  436.  
  437. static int drawData(display disp)
  438. {
  439.      float    fontHeight;
  440.  
  441.      if (disp->ntuple == NULL) return 0;
  442.  
  443.      if (disp->ntuple->ndata == 0)
  444.      { 
  445.       fontHeight= MIN(disp->drawRect.size.width*0.05,24.0);
  446.       drawText("No Data in Tuple",
  447.            disp->marginRect.origin.x+disp->marginRect.size.width/2.0,
  448.            disp->marginRect.origin.y+disp->marginRect.size.height/2.0,
  449.            fontHeight, 0, 'c', 'c');
  450.       return 0;
  451.      }
  452.      
  453.      switch (disp->graphtype) 
  454.      {
  455.      case HISTOGRAM:
  456.      case XYPLOT:
  457.      case STRIPCHART:
  458.       drawData1D( disp );
  459.       break;
  460.  
  461.      case COLORPLOT:        /* 2D COLOR */
  462.       drawColor2D(disp);
  463.       break;
  464.       
  465.      case SCATTERPLOT:        /* 2D SCATTER */
  466.       drawScatter2D(disp);
  467.       break;
  468.       
  469.      case LEGOPLOT:        /* 2D LEGO */
  470.       drawLego2D(disp);
  471.       break;
  472.      }
  473.      
  474.      
  475.      return 0;
  476. }
  477.  
  478. static int drawData1D(display disp)
  479. {
  480.      float *xy = NULL, *lego = NULL, *xerr = NULL, *yerr = NULL;
  481.      int *over = NULL, xmin_pt = 0, npts;
  482.      struct maxs limits;
  483.      
  484.      /*
  485.       * first get the appropriate data, depending on the graphtype.
  486.       */
  487.      switch (disp->graphtype) 
  488.      {
  489.      case HISTOGRAM:        /* Histogra */
  490.       npts = getHistoData(disp,&xy,&lego,&xerr,&yerr,&over,&limits);
  491.       if (npts == 0) return 0;
  492.       if (npts < 0) 
  493.       {
  494.            h_error("h_plot - error getting bin data");
  495.            return -1;
  496.       }
  497.  
  498.       if (disp->yAxis.flags.autoScale)
  499.       {
  500.            if (limits.yh < limits.yl)
  501.            {
  502.             /* must be no points in range. */
  503.             return 0;
  504.            }             
  505.            else if (limits.yh == limits.yl)
  506.            {
  507.             /* must be only on point in range. */
  508.             disp->yAxis.low = limits.yh - 0.5;
  509.             disp->yAxis.high = limits.yh + 0.5;
  510.            }
  511.            else
  512.            {
  513.             if (limits.yh > 0.0)
  514.              disp->yAxis.high = limits.yh;
  515.             else
  516.             {
  517.              if (disp->yAxis.flags.log)
  518.              {
  519.                   h_error("All data < 0 on log axis");
  520.                   return -1;
  521.              }
  522.              disp->yAxis.high = 0.0;
  523.             }
  524.             
  525.             if (limits.yl < 0.0 || disp->yAxis.flags.log)
  526.              disp->yAxis.low = limits.yl;
  527.             else
  528.              disp->yAxis.low = 0.0;
  529.            }
  530.       }
  531.       else if (disp->yAxis.flags.log && disp->yAxis.low <= 0.0)
  532.       {
  533.            if (limits.yl > 0.0)
  534.             disp->yAxis.low = limits.yl;
  535.            else
  536.             disp->yAxis.low = pow(10.0, FLT_MIN);
  537.            if (disp->yAxis.high <= disp->yAxis.low)
  538.             disp->yAxis.high = disp->yAxis.low*(1.0+NUM_FUZZ);
  539.       }
  540.  
  541.       break;
  542.       
  543.      case XYPLOT:
  544.      case STRIPCHART:
  545.       npts = getXYData(disp,&xy,&xerr,&yerr,&over,&limits,&xmin_pt);
  546.       if (npts == 0) return 0;
  547.       if (npts < 0) 
  548.       {
  549.            h_error("h_plot - error getting data for x-y plot");
  550.            return -1;
  551.       }
  552.  
  553.       if (disp->graphtype == XYPLOT) xmin_pt = 0;
  554.       
  555.       /* 
  556.        * autoscale axes 
  557.        */
  558.       if (disp->xAxis.flags.autoScale)
  559.       {
  560.            if (limits.xh > limits.xl)
  561.            {
  562.             disp->xAxis.low = limits.xl;
  563.             disp->xAxis.high = limits.xh;
  564.            }
  565.            else if (limits.xh == limits.xl)
  566.            {
  567.             /* must be only on point in range. */
  568.             disp->xAxis.low = limits.xl - 0.5;
  569.             disp->xAxis.high = limits.xh + 0.5;
  570.            }
  571.            else
  572.            {
  573.             /* must be no points in range. */
  574.             return 0;
  575.            }             
  576.            h_adjustAxis(&(disp->xAxis.low), &(disp->xAxis.high),
  577.                 0, disp->xAxis.flags.log);
  578.       }
  579.       else if (disp->xAxis.flags.log && disp->xAxis.low <= 0.0)
  580.       {
  581.            if (limits.xl > 0.0)
  582.             disp->xAxis.low = limits.xl;
  583.            else
  584.             disp->xAxis.low = pow(10.0, FLT_MIN);
  585.            if (disp->xAxis.high <= disp->xAxis.low)
  586.             disp->xAxis.high = disp->xAxis.low*(1.0+NUM_FUZZ);
  587.       }
  588.  
  589.       if (disp->yAxis.flags.autoScale)
  590.       {
  591.            if (limits.yh > limits.yl)
  592.            {
  593.             disp->yAxis.low = limits.yl;
  594.             disp->yAxis.high = limits.yh;
  595.            }
  596.            else if (limits.yh == limits.yl)
  597.            {
  598.             /* must be only on point in range. */
  599.             disp->yAxis.low = limits.yl - 0.5;
  600.             disp->yAxis.high = limits.yh + 0.5;
  601.            }
  602.            else
  603.            {
  604.             /* must be no points in range. */
  605.             return 0;
  606.            }             
  607.       }
  608.       else if (disp->yAxis.flags.log && disp->yAxis.low <= 0.0)
  609.       {
  610.            if (limits.yl > 0.0)
  611.             disp->yAxis.low = limits.yl;
  612.            else
  613.             disp->yAxis.low = pow(10.0, FLT_MIN);
  614.            if (disp->yAxis.high <= disp->yAxis.low)
  615.             disp->yAxis.high = disp->yAxis.low*(1.0+NUM_FUZZ);
  616.       }
  617.       
  618.       break;
  619.       
  620.      default:
  621.       h_error("hippo error: invalid disp->graphtype\n");
  622.       return -1;
  623.       break;
  624.      }
  625.  
  626.      if (disp->yAxis.flags.autoScale)
  627.       h_adjustAxis(&(disp->yAxis.low), &(disp->yAxis.high),
  628.                0, disp->yAxis.flags.log );
  629.      
  630.      /*
  631.       * init the plot device
  632.       */
  633.      if (!init_done)
  634.      {
  635.       initPlot( disp );
  636.       init_done = 1;
  637.      }
  638.  
  639.      /*
  640.       * draw the points, lines etc.
  641.       */
  642.  
  643.      /* draw points */
  644.      if ( disp->drawtype & POINT )
  645.       drawPoint1D(disp, xy, over, npts);
  646.      
  647.      /* draw error bars */
  648.      if ( disp->drawtype & ERRBAR )
  649.      {
  650.       if (yerr != NULL) drawError1D(disp,xy,yerr,over,npts,YERROR);
  651.       if (xerr != NULL) drawError1D(disp,xy,xerr,over,npts,XERROR);
  652.      }
  653.      
  654.      
  655.      /* join points */
  656.      if ( disp->drawtype & LINE )
  657.       drawLine1D(disp,xy,over,npts,xmin_pt,disp->lineStyle);
  658.      
  659.      /* draw bars */
  660.      if ( (disp->drawtype & BOX) && disp->graphtype==HISTOGRAM )
  661.       drawLego1D(disp, lego, over, npts);
  662.      
  663.      free(lego);
  664.      free(xy);
  665.      free(xerr);
  666.      free(yerr);
  667.      free(over);
  668.      
  669.      return 0;
  670. }
  671.  
  672.  
  673. static int initPlot(display disp)
  674. {
  675.      int rc;
  676.      rectangle userRect;
  677.  
  678.      if (disp->xAxis.flags.log)
  679.      {
  680.       userRect.origin.x = log10(disp->xAxis.low);
  681.       userRect.size.width = log10(disp->xAxis.high) - 
  682.            log10(disp->xAxis.low);
  683.      }
  684.      else
  685.      {
  686.       userRect.origin.x = disp->xAxis.low;
  687.       userRect.size.width = disp->xAxis.high - disp->xAxis.low;
  688.      }
  689.      if (disp->yAxis.flags.log)
  690.      {
  691.       userRect.origin.y = log10(disp->yAxis.low);
  692.       userRect.size.height = log10(disp->yAxis.high)
  693.            - log10(disp->yAxis.low);
  694.      }
  695.      else
  696.      {
  697.       userRect.origin.y = disp->yAxis.low;
  698.       userRect.size.height = disp->yAxis.high - disp->yAxis.low;
  699.      }
  700.      
  701.      switch (plot_drvr)
  702.      {
  703.       NeXTFunc(initPlot,(&disp->drawRect, &disp->marginRect, &userRect));
  704.       UPFunc(initPlot,(&disp->drawRect, &disp->marginRect, &userRect));
  705.       MACFunc(initPlot,(&disp->drawRect, &disp->marginRect, &userRect));
  706.       PSFunc(initPlot,(&disp->drawRect, &disp->marginRect, &userRect));
  707.       
  708. #ifdef _XIV_PLOT_
  709.      case XIVPLOT:
  710.       initPlot_XIV(painter,canvas);
  711.       setHistoCoords_XIV(&disp->marginRect, &userRect);
  712.       rc = 0;
  713.       break;
  714. #endif
  715.  
  716. #ifdef _X11_PLOT_
  717.      case X11PLOT:
  718.       initPlot_X11(dpy,screen,drawable,gc);
  719.       setHistoCoords_X11(&disp->drawRect, &disp->marginRect, &userRect);
  720.       rc = 0;
  721.       break;
  722. #endif
  723.  
  724.      default:
  725.       rc = -1;
  726.      }
  727.      
  728.      return rc;
  729. }
  730.  
  731.  
  732.  
  733. static int endPlot(display disp)
  734. {
  735.      int rc;
  736.      
  737.      switch (plot_drvr)
  738.      {
  739.       UPFunc(endPlot,());
  740.             
  741.      default:
  742.       rc = 0;
  743.      }
  744.      
  745.      return rc;
  746. }
  747.  
  748.  
  749.  
  750. static int drawLabels( display disp )
  751. {
  752.      float x, y;
  753.      float fontSize;
  754.      char string[80];
  755.      
  756.      /*
  757.       * title
  758.       */
  759.      fontSize = disp->drawRect.size.width*0.05;
  760.      fontSize = MIN(fontSize, 
  761.             (disp->drawRect.size.height - 
  762.              disp->marginRect.size.height - 2*YPADDING(disp) -
  763.              (disp->marginRect.origin.y-disp->drawRect.origin.y)));
  764.      x = disp->marginRect.origin.x + 0.5 * disp->marginRect.size.width;
  765.      y = disp->drawRect.origin.y + disp->drawRect.size.height - YPADDING(disp);
  766.      h_expandLabel(string,disp->title,80,disp);
  767.      if (fontSize > disp->marginRect.size.width/strlen(string)*2)
  768.      {
  769.       fontSize = disp->drawRect.size.width/strlen(string)*2;
  770.       x = disp->drawRect.origin.x + 0.5 * disp->drawRect.size.width;
  771.      }
  772.      
  773.      if (drawText(string, x, y, fontSize,0.0,'c','t') != 0)
  774.      {
  775.       h_error("Error drawing plot title");
  776.       return -1;
  777.      }
  778.  
  779.      /*
  780.       * x axis label
  781.       */
  782.      fontSize = MIN(disp->drawRect.size.width*0.04,14.0);
  783.      fontSize = MIN(fontSize, 
  784.              (disp->marginRect.origin.y-disp->drawRect.origin.y)/2.0);
  785.      fontSize = MIN(fontSize, 
  786.             disp->drawRect.size.width/strlen(disp->xAxis.label)*2);
  787.      y = disp->drawRect.origin.y + YPADDING(disp);
  788.      h_expandLabel(string,disp->xAxis.label,80,disp);
  789.      if (drawText(string, x, y, fontSize,0.0,'c','b') != 0)
  790.      {
  791.       h_error("Error drawing x axis label");
  792.       return -1;
  793.      }
  794.      
  795.      /*
  796.       * y axis label
  797.       */
  798.      fontSize = MIN(disp->drawRect.size.width*0.04,14.0);
  799.      fontSize = MIN(fontSize, 
  800.             disp->drawRect.size.height/strlen(disp->yAxis.label)*2);
  801.      x = disp->drawRect.origin.x + XPADDING(disp);
  802.      y = disp->marginRect.origin.y + disp->marginRect.size.height/2.0;
  803.      h_expandLabel(string,disp->yAxis.label,80,disp);
  804.      if (drawText(string, x, y, fontSize,90.0,'c','t') != 0)
  805.      {
  806.       h_error("Error drawing y axis label");
  807.       return -1;
  808.      }
  809.      
  810.      
  811.      return 0;
  812. }
  813.  
  814.      
  815.  
  816. static int drawText(char *s, float x, float y, float fontsize, float angle,
  817.          char xp, char yp )
  818. {
  819.      int rc;
  820.      
  821.      PlotSwitch(plot_drvr,drawText,(s, x, y, fontsize, angle, xp, yp));
  822.      
  823.      return rc;
  824. }
  825.  
  826.  
  827. static int drawAxisBox( display disp )
  828. {
  829.      int rc = 0;
  830.      float xy[10];
  831.  
  832.      if (disp->xAxis.flags.log)
  833.      {
  834.       xy[0] = xy[2] = xy[8] = log10(disp->xAxis.low);
  835.       xy[4] = xy[6] = log10(disp->xAxis.high);
  836.      }
  837.      else
  838.      {
  839.       xy[0] = xy[2] = xy[8] = disp->xAxis.low;
  840.       xy[4] = xy[6] = disp->xAxis.high;
  841.      }
  842.      if (disp->yAxis.flags.log)
  843.      {
  844.       xy[1] = xy[7] = xy[9] = log10(disp->yAxis.low);
  845.       xy[3] = xy[5] = log10(disp->yAxis.high);
  846.      }
  847.      else
  848.      {
  849.       xy[1] = xy[7] = xy[9] = disp->yAxis.low;
  850.       xy[3] = xy[5] = disp->yAxis.high;
  851.      }
  852.      
  853.      PlotSwitch(plot_drvr,drawLine,(xy,5, SOLID));
  854.  
  855.      return rc;
  856. }
  857.  
  858. #define N__TICKS 20
  859.  
  860. static int drawTicks(display disp, binding_t axis)
  861. {
  862.      int nticks = 0;
  863.      int i, rc=0;
  864.      
  865.      float ticks[N__TICKS];
  866.      char labels[N__TICKS][10];
  867.      float magnitude,y,yr,startTick,tickSize;
  868.      float x=0.0;
  869.      char string[70];
  870.      float fontSize;
  871.      float pmag;
  872.      char pstr[10];
  873.      int nLogTicks;
  874.      float logTicks[5];
  875.      float maglow, maghigh, magrng, magStep;
  876.      
  877.      axis_t *thisaxis;
  878.      char xalign='c', yalign='c';
  879.      
  880.      fontSize = MIN(disp->drawRect.size.width*0.04,14.0);
  881.  
  882.      switch (axis)
  883.      {
  884.      case XAXIS:
  885.       thisaxis = &disp->xAxis;
  886.       break;
  887.      case YAXIS:
  888.       thisaxis = &disp->yAxis;
  889.       break;
  890.      default:
  891.       return -1;
  892.      }
  893.      
  894.      /* draw ticks on y axis */
  895.      if (thisaxis->low >= thisaxis->high)
  896.      {
  897.       h_error("h_plot: axis low > high");
  898.       sprintf(string,"low = %f, high = %f\n",thisaxis->low,
  899.           thisaxis->high);
  900.       h_error(string);
  901.       return -1;
  902.      }
  903.  
  904.      if (!thisaxis->flags.log)
  905.      {
  906.       tickSize = calcTicks((thisaxis->high -
  907.                 thisaxis->low), &magnitude);
  908.       startTick = ceil( thisaxis->low / tickSize) * tickSize;
  909.  
  910.       if (fabs(magnitude) <= 3.0)
  911.            pmag = 0.0;
  912.       else 
  913.       {
  914.            if (startTick != 0.0)
  915.             pmag = floor(log10(fabs(startTick)));
  916.            else
  917.             pmag = magnitude;
  918.       }
  919.                        
  920.       sprintf(pstr,"%%1.%df",(int)MAX((pmag-magnitude),0.0));
  921.  
  922.       y = startTick;
  923.       while (y <= thisaxis->high*(1.0+NUM_FUZZ))
  924.       {
  925.            if (nticks >= N__TICKS)
  926.            {
  927.             h_error("Too many ticks along y axis.");
  928.             return -1;
  929.            }
  930.            
  931.            yr = floor(y/pow(10.0,magnitude) + 0.5);
  932.            ticks[nticks] = yr * pow(10.0,magnitude);
  933.            sprintf(labels[nticks],pstr,yr*pow(10.0,magnitude-pmag));
  934.            nticks++;
  935.            y += tickSize;
  936.       }
  937.       if (fabs(magnitude) <= 3.0) magnitude = 0.0;
  938.      }
  939.      else
  940.      {
  941.       maghigh = ceil(log10(thisaxis->high));
  942.       maglow = floor(log10(thisaxis->low));
  943.       magrng = maghigh - maglow;
  944.       
  945.       if (magrng <=3)
  946.       {
  947.            nLogTicks = 3;
  948.            logTicks[0] = 1.0;
  949.            logTicks[1] = 2.0;
  950.            logTicks[2] = 5.0;
  951.            magStep = 1.0;
  952.       }
  953.       else 
  954.       {
  955.            nLogTicks = 1;
  956.            logTicks[0] = 1.0;
  957.            if (magrng <= 7) 
  958.             magStep = 1.0;
  959.            else 
  960.             magStep = 2.0;
  961.       }
  962.            
  963.       if (nLogTicks == 3 && (fabs(maglow)>3 || fabs(maghigh)>3))
  964.            pmag = maglow;
  965.       else
  966.            pmag = 0.0;
  967.       magnitude = maglow;
  968.       i = 0;
  969.       while ((y=logTicks[i]*pow(10.0,magnitude)) <
  970.          thisaxis->high*(1.0+NUM_FUZZ))
  971.       {
  972.            if (nticks >= N__TICKS)
  973.            {
  974.             h_error("Too many ticks along y axis.");
  975.             return -1;
  976.            }
  977.            if (y >= thisaxis->low)
  978.            {
  979.             ticks[nticks] = log10(y);
  980.             /*
  981.              * be careful: there is a bug in the NeXT (s)printf 
  982.              *   routine when you do, eg. printf("%1.0g",0.01);
  983.              */
  984.             if ((magnitude-pmag) > 4 || (magnitude-pmag) < -3)
  985.              strcpy(pstr,"%1.0e");
  986.             else
  987.              sprintf(pstr,"%%1.%df",
  988.                  (int)((magnitude-pmag)>0?
  989.                        0:-(magnitude-pmag)));
  990.             sprintf(labels[nticks],pstr,y*pow(10.0,-pmag));
  991.             nticks++;
  992.            }
  993.            
  994.            i++;
  995.            if (i>=nLogTicks)
  996.            {
  997.             i = 0;
  998.             magnitude += magStep;
  999.            }
  1000.       }
  1001.      }
  1002.      
  1003.      /*
  1004.       * Plot the tick marks
  1005.       */
  1006.      switch (axis)
  1007.      {
  1008.      case XAXIS:
  1009.       drawXTicks(ticks,nticks,thisaxis->tickLength,
  1010.              thisaxis->flags.tickLocation);
  1011.       break;
  1012.      case YAXIS:
  1013.       drawYTicks(ticks,nticks,thisaxis->tickLength,
  1014.              thisaxis->flags.tickLocation);
  1015.       break;
  1016.      default:
  1017.       return -1;
  1018.      }
  1019.      if (rc != 0) return rc;
  1020.  
  1021.      switch (axis)
  1022.      {
  1023.      case XAXIS:
  1024.       y = disp->marginRect.origin.y - YPADDING(disp);
  1025.       fontSize = MIN(fontSize, 
  1026.              (disp->marginRect.origin.y -
  1027.               disp->drawRect.origin.y)/2.0);
  1028.       xalign = 'c';
  1029.       yalign = 't';
  1030.       break;
  1031.      case YAXIS:
  1032.       x = disp->marginRect.origin.x - XPADDING(disp);
  1033.       yr = MIN(disp->drawRect.size.width*0.04,14.0);
  1034.       yr = MIN(fontSize, 
  1035.             disp->drawRect.size.height/strlen(disp->yAxis.label)*2);
  1036.       fontSize = MIN(fontSize, 
  1037.              (disp->marginRect.origin.x -
  1038.               disp->drawRect.origin.x - yr)
  1039.              /strlen(labels[nticks-1]));
  1040.       xalign = 'r';
  1041.       yalign = 'c';
  1042.       break;
  1043.      default:
  1044.       return -1;
  1045.      }
  1046.  
  1047.      for (i=0; i<nticks; i++ )
  1048.      {
  1049.       if (!thisaxis->flags.log)
  1050.       {
  1051.            switch (axis)
  1052.            {
  1053.            case XAXIS:
  1054.             x = disp->marginRect.origin.x +
  1055.              (ticks[i]-thisaxis->low) * 
  1056.                   disp->marginRect.size.width
  1057.                    /(thisaxis->high - thisaxis->low);
  1058.             break;
  1059.            case YAXIS:
  1060.             y = disp->marginRect.origin.y +
  1061.              (ticks[i]-thisaxis->low) * 
  1062.                   disp->marginRect.size.height 
  1063.                    /(thisaxis->high - thisaxis->low);
  1064.             break;
  1065.            default:
  1066.             return -1;
  1067.            }
  1068.       }
  1069.       else
  1070.       {
  1071.            switch (axis)
  1072.            {
  1073.            case XAXIS:
  1074.             x = disp->marginRect.origin.x +
  1075.              (ticks[i]-log10(thisaxis->low))
  1076.                   * disp->marginRect.size.width
  1077.                    /log10(thisaxis->high/thisaxis->low);
  1078.             break;
  1079.            case YAXIS:
  1080.             y = disp->marginRect.origin.y +
  1081.              (ticks[i]-log10(thisaxis->low))
  1082.                   * disp->marginRect.size.height 
  1083.                    /log10(thisaxis->high/thisaxis->low);
  1084.             break;
  1085.            default:
  1086.             return -1;
  1087.            }
  1088.       }
  1089.  
  1090.       if (drawText(labels[i], x, y, fontSize, 0.0,
  1091.                xalign, yalign ) != 0)
  1092.       {
  1093.            h_error("Error draw label on axis.");
  1094.            return -1;
  1095.       }
  1096.      }      
  1097.  
  1098.      if (pmag != 0.0)
  1099.      {
  1100.       switch (axis)
  1101.       {
  1102.       case XAXIS:
  1103.            x = disp->marginRect.origin.x + disp->marginRect.size.width
  1104.             + XPADDING(disp);
  1105.            y = disp->marginRect.origin.y;
  1106.            break;
  1107.       case YAXIS:
  1108.            x = disp->marginRect.origin.x;
  1109.            y = disp->marginRect.origin.y + disp->marginRect.size.height
  1110.             + YPADDING(disp);
  1111.            break;
  1112.       default:
  1113.            return -1;
  1114.       }
  1115.       drawMag(x, y, (int)pmag, fontSize*0.75 );
  1116.      }
  1117.      
  1118.      return 0;
  1119. }
  1120.  
  1121. static int drawXTicks(float *ticks, int nticks, float tickLength, char tickLoc )
  1122. {
  1123.      int rc = 0;
  1124.      
  1125.      if (tickLoc & PLOTBOTTOM)
  1126.      {
  1127.       PlotSwitch(plot_drvr,drawXTicks,(ticks,nticks,tickLength,0));
  1128.      }
  1129.      if (tickLoc & PLOTTOP)
  1130.      {
  1131.       PlotSwitch(plot_drvr,drawXTicks,(ticks,nticks,tickLength,1));
  1132.      }
  1133.      return rc;
  1134. }
  1135.  
  1136.  
  1137. static int drawYTicks(float *ticks, int nticks, float tickLength, char tickLoc )
  1138. {
  1139.      int rc = 0;
  1140.      
  1141.      if (tickLoc & PLOTLEFT)
  1142.      {
  1143.       PlotSwitch(plot_drvr,drawYTicks,(ticks,nticks,tickLength,0));
  1144.      }
  1145.      if (tickLoc & PLOTRIGHT)
  1146.      {
  1147.       PlotSwitch(plot_drvr,drawYTicks,(ticks,nticks,tickLength,1));
  1148.      }
  1149.      return rc;
  1150. }
  1151.  
  1152.  
  1153. static int drawMag( float x, float y, int mag, float fontSize )
  1154. {
  1155.      int rc;
  1156.  
  1157.      PlotSwitch(plot_drvr,drawMag,( x, y, mag, fontSize ));
  1158.      
  1159.      return rc;
  1160. }
  1161.      
  1162.  
  1163.  
  1164. static int drawLego1D(display disp, float *xylego, int *over, 
  1165.               int npts)
  1166. {
  1167.      int rc = 0;
  1168.      int end;
  1169.      int i_over;
  1170.      float ylow, yhigh;
  1171.      
  1172.      if (disp->yAxis.flags.log)
  1173.      {
  1174.       yhigh = log10(disp->yAxis.high);
  1175.       ylow = log10(disp->yAxis.low);
  1176.      }
  1177.      else
  1178.      {
  1179.       yhigh = disp->yAxis.high;
  1180.       ylow = disp->yAxis.low;
  1181.      }
  1182.      
  1183.      /*
  1184.       * first, check the first group of points, since
  1185.       * it is not associated with a bin. (last group is check
  1186.       * by last element in over)
  1187.       */
  1188.      if (xylego[1] > yhigh) xylego[1] = yhigh;
  1189.      if (xylego[1] < ylow) xylego[1] = ylow;
  1190.      if (xylego[3] > yhigh) xylego[3] = yhigh;
  1191.      if (xylego[3] < ylow) xylego[3] = ylow;
  1192.           
  1193.      i_over = 0;
  1194.      do
  1195.      {
  1196.       end = over[i_over++];
  1197.       if (xylego[4*(end+1)+1] > yhigh) xylego[4*(end+1)+1] = yhigh;
  1198.       if (xylego[4*(end+1)+1] < ylow) xylego[4*(end+1)+1] = ylow;
  1199.       if (xylego[4*(end+1)+3] > yhigh) xylego[4*(end+1)+3] = yhigh;
  1200.       if (xylego[4*(end+1)+3] < ylow) xylego[4*(end+1)+3] = ylow;
  1201.      }
  1202.      while (end < npts);
  1203.  
  1204.  
  1205.      PlotSwitch(plot_drvr,drawLine,( xylego, 2*(npts+2), SOLID ));
  1206.  
  1207.      return rc;
  1208. }
  1209.  
  1210.  
  1211. static int drawPoint1D(display disp, float *xy, int *over, int npts)
  1212. {
  1213.      int rc=0;
  1214.      int start = -1, end;
  1215.      int i_over=0;
  1216.           
  1217.      float xlow, ylow;
  1218.      float xhigh, yhigh;
  1219.      
  1220.      if (disp->xAxis.flags.log)
  1221.      {
  1222.       xhigh = log10(disp->xAxis.high);
  1223.       xlow = log10(disp->xAxis.low);
  1224.      }
  1225.      else
  1226.      {
  1227.       xhigh = disp->xAxis.high;
  1228.       xlow = disp->xAxis.low;
  1229.      }
  1230.      if (disp->yAxis.flags.log)
  1231.      {
  1232.       yhigh = log10(disp->yAxis.high);
  1233.       ylow = log10(disp->yAxis.low);
  1234.      }
  1235.      else
  1236.      {
  1237.       yhigh = disp->yAxis.high;
  1238.       ylow = disp->yAxis.low;
  1239.      }
  1240.      
  1241.      do
  1242.      {
  1243.       /*
  1244.        * Check that points marked as over are really over (it may be
  1245.        * that error bar is over).
  1246.        */
  1247.       do 
  1248.       {
  1249.            if (start == -1)
  1250.             start = 0;
  1251.            else
  1252.             start = over[i_over++]+1;
  1253.            end = over[i_over];
  1254.  
  1255.            while (end<npts)
  1256.            {
  1257.             /* include some fuzz in comparisons */
  1258.             if (xy[2*end+1]<(ylow*(1.0-NUM_FUZZ)) || 
  1259.             xy[2*end+1]>(yhigh*(1.0+NUM_FUZZ))) break;
  1260.             if (xy[2*end]<(xlow*(1.0-NUM_FUZZ)) || 
  1261.             xy[2*end]>(xhigh*(1.0+NUM_FUZZ))) break;
  1262.             end = over[++i_over];
  1263.            }
  1264.       }
  1265.       while ( (end-start) <= 0 && start<npts );
  1266.             
  1267.       if (start >= npts) continue;
  1268.       
  1269.       PlotSwitch(plot_drvr,drawPoints,(&(xy[2*start]),end-start,
  1270.                        disp->plotSymbol,disp->symbolSize));
  1271.      }
  1272.      while (rc == 0 && end < npts && start < npts);
  1273.      
  1274.      return rc;
  1275. }
  1276.  
  1277.  
  1278. static int drawLine1D(display disp, float *xy, int *over, 
  1279.               int npts, int xmin_pt, linestyle_t ls)
  1280. {
  1281.      int rc = 0;
  1282.      int start, end;
  1283.      int s_saved, e_saved;
  1284.      int i_over = 0;
  1285.      float *xy_alt;
  1286.      int *over_alt;
  1287.      float xlow, ylow;
  1288.      float xhigh, yhigh;
  1289.      
  1290.      float start_save[2],end_save[2];
  1291.  
  1292.      if (npts < 2) return 0;
  1293.      
  1294.      if (xmin_pt > 0)
  1295.      {
  1296.       if ( (xy_alt = (float *)malloc( 2*npts*sizeof(float) ))
  1297.           == NULL)
  1298.       {
  1299.            h_error("drawLine1D - ran out of memory");
  1300.            return -1;
  1301.       }
  1302.       if ( (over_alt = (int *)malloc( (npts+1)*sizeof(int) ))
  1303.           == NULL)
  1304.       {
  1305.            h_error("drawLine1D - ran out of memory");
  1306.            return -1;
  1307.       }
  1308.       memcpy((char *)xy_alt, (char *)&xy[2*xmin_pt],
  1309.          2*(npts-xmin_pt)*sizeof(float) );
  1310.       memcpy((char *)&xy_alt[2*(npts-xmin_pt)], (char *)xy,
  1311.          2*xmin_pt*sizeof(float) );
  1312.       for (i_over=0; over[i_over]<npts; i_over++ )
  1313.       {
  1314.            if (over[i_over] >= xmin_pt)
  1315.             over_alt[i_over] = over[i_over] - xmin_pt;
  1316.            else
  1317.             over_alt[i_over] = over[i_over] + npts - xmin_pt;
  1318.       }
  1319.       over_alt[i_over++] = npts;
  1320.       if (i_over > 1)
  1321.            qsort( over_alt, (size_t)i_over, sizeof(int), intcmp );
  1322.      }
  1323.      else
  1324.      {
  1325.       over_alt = over;
  1326.       xy_alt = xy;
  1327.      }
  1328.           
  1329.      if (disp->xAxis.flags.log)
  1330.      {
  1331.       xhigh = log10(disp->xAxis.high);
  1332.       xlow = log10(disp->xAxis.low);
  1333.      }
  1334.      else
  1335.      {
  1336.       xhigh = disp->xAxis.high;
  1337.       xlow = disp->xAxis.low;
  1338.      }
  1339.      if (disp->yAxis.flags.log)
  1340.      {
  1341.       yhigh = log10(disp->yAxis.high);
  1342.       ylow = log10(disp->yAxis.low);
  1343.      }
  1344.      else
  1345.      {
  1346.       yhigh = disp->yAxis.high;
  1347.       ylow = disp->yAxis.low;
  1348.      }
  1349.      
  1350.      i_over = 0;
  1351.      start = -1;
  1352.      do
  1353.      {
  1354.       /*
  1355.        * Check that points marked as over are really over (it may be
  1356.        * that error bar is over). Interpolate to find point where
  1357.        * line crosses axes.
  1358.        */
  1359.       s_saved = 0;
  1360.       e_saved = 0;
  1361.  
  1362.       do 
  1363.       {
  1364.            if (start == -1)
  1365.             start = 0;
  1366.            else
  1367.             start = over_alt[i_over++]+1;
  1368.            end = over_alt[i_over];
  1369.  
  1370.            while (end<npts)
  1371.            {
  1372.             /* include some fuzz in comparisons */
  1373.             if (xy_alt[2*end+1]<(ylow*(1.0-NUM_FUZZ)) || 
  1374.             xy_alt[2*end+1]>(yhigh*(1.0+NUM_FUZZ))) break;
  1375.             if (xy_alt[2*end]<(xlow*(1.0-NUM_FUZZ)) ||
  1376.             xy_alt[2*end]>(xhigh*(1.0+NUM_FUZZ))) break;
  1377.             end = over_alt[++i_over];
  1378.            }
  1379.       }
  1380.       while ( (end-start) <= 0 && start<npts );
  1381.             
  1382.       if (start >= npts) continue;
  1383.  
  1384.       if (start > 0)
  1385.       {
  1386.            memcpy(start_save,&(xy_alt[2*(start-1)]),2*sizeof(float) );
  1387.            s_saved = 1;
  1388.            box_cross( &xy_alt[2*(start-1)], &xy_alt[2*start], disp);
  1389.            start--;
  1390.       }
  1391.       if (end < npts)
  1392.       {
  1393.            memcpy(end_save,&(xy_alt[2*end]),2*sizeof(float) );
  1394.            e_saved = 1;
  1395.            box_cross( &xy_alt[2*end], &xy_alt[2*(end-1)], disp);
  1396.            end++;
  1397.       }
  1398.  
  1399.       PlotSwitch(plot_drvr,drawLine,
  1400.              (&(xy_alt[2*start]),end-start,ls));
  1401.  
  1402.       if (s_saved)
  1403.            memcpy(&(xy_alt[2*start]),start_save,2*sizeof(float) );
  1404.       if (e_saved)
  1405.            memcpy(&(xy_alt[2*(end-1)]),end_save,2*sizeof(float) );
  1406.  
  1407.  
  1408.      }
  1409.      while (rc == 0 && end < npts && start < npts);
  1410.  
  1411.      if (xmin_pt != 0)
  1412.      {
  1413.       free(xy_alt);
  1414.       free(over_alt);
  1415.      }
  1416.      
  1417.      return rc;
  1418. }
  1419.  
  1420. /*
  1421.  * integer comparison for qsort.
  1422.  */
  1423. int intcmp(const void *i1, const void *i2)
  1424. {
  1425.      if ((int *)i1 > (int *)i2)
  1426.       return 1;
  1427.      else if ((int *)i1 == (int *)i2)
  1428.       return 0;
  1429.      else 
  1430.       return -1;
  1431. }
  1432.  
  1433. /*
  1434.  * find point where interpolation between p1 and p2 cross the 
  1435.  *  axes box.
  1436.  */
  1437. static void box_cross( float *p1, float *p2, display disp )
  1438. {
  1439.      float xlow,ylow, xhigh, yhigh;
  1440.      float x_int1,x_int2,y_int1,y_int2;
  1441.      
  1442.      if (disp->xAxis.flags.log)
  1443.      {
  1444.       xlow = log10(disp->xAxis.low);
  1445.       xhigh = log10(disp->xAxis.high);
  1446.      }
  1447.      else
  1448.      {
  1449.       xlow = disp->xAxis.low;
  1450.       xhigh = disp->xAxis.high;
  1451.      }
  1452.      if (disp->yAxis.flags.log)
  1453.      {
  1454.       ylow = log10(disp->yAxis.low);
  1455.       yhigh = log10(disp->yAxis.high);
  1456.      }
  1457.      else
  1458.      {
  1459.       ylow = disp->yAxis.low;
  1460.       yhigh = disp->yAxis.high;
  1461.      }
  1462.      
  1463.      x_int1 = p1[0] + (ylow-p1[1])*(p2[0]-p1[0])/(p2[1]-p1[1]);
  1464.      if (x_int1 >= xlow && x_int1 <= xhigh &&
  1465.      ylow >= p1[1] && ylow <= p2[1])
  1466.      {
  1467.       p1[0] = x_int1;
  1468.       p1[1] = ylow;
  1469.       return;
  1470.      }
  1471.  
  1472.      x_int2 = p1[0] + (yhigh-p1[1])*(p2[0]-p1[0])/(p2[1]-p1[1]);
  1473.      if (x_int2 >= xlow && x_int2 <= xhigh &&
  1474.      yhigh <= p1[1] && yhigh >= p2[1])
  1475.      {
  1476.       p1[0] = x_int2;
  1477.       p1[1] = yhigh;
  1478.       return;
  1479.      }
  1480.  
  1481.      y_int1 = p1[1] + (xlow-p1[0])*(p2[1]-p1[1])/(p2[0]-p1[0]);
  1482.      if (y_int1 >= ylow && y_int1 <= yhigh &&
  1483.      xlow >= p1[0] && xlow <= p2[0])
  1484.      {
  1485.       p1[0] = xlow;
  1486.       p1[1] = y_int1;
  1487.       return;
  1488.      }
  1489.  
  1490.      y_int2 = p1[1] + (xhigh-p1[0])*(p2[1]-p1[1])/(p2[0]-p1[0]);
  1491.      if (y_int2 >= ylow && y_int1 <= yhigh &&
  1492.      xhigh <= p1[0] && xhigh >= p2[0])
  1493.      {
  1494.       p1[0] = xhigh;
  1495.       p1[1] = y_int2;
  1496.       return;
  1497.      }
  1498. }
  1499.  
  1500.  
  1501. /*
  1502.  * draw errors - err_type specifies whether they are x or y errors.
  1503.  */
  1504. static int drawError1D(display disp, float *xy, float *err, 
  1505.                int *over, int npts, int err_type)
  1506. {
  1507.      int rc = 0;
  1508.      int start = -1;
  1509.      int end;
  1510.      int i_over = 0;
  1511.      
  1512.      float xlow, ylow;
  1513.      float xhigh, yhigh;
  1514.      
  1515.      if (disp->xAxis.flags.log)
  1516.      {
  1517.       xhigh = log10(disp->xAxis.high);
  1518.       xlow = log10(disp->xAxis.low);
  1519.      }
  1520.      else
  1521.      {
  1522.       xhigh = disp->xAxis.high;
  1523.       xlow = disp->xAxis.low;
  1524.      }
  1525.      if (disp->yAxis.flags.log)
  1526.      {
  1527.       yhigh = log10(disp->yAxis.high);
  1528.       ylow = log10(disp->yAxis.low);
  1529.      }
  1530.      else
  1531.      {
  1532.       yhigh = disp->yAxis.high;
  1533.       ylow = disp->yAxis.low;
  1534.      }
  1535.      
  1536.      do
  1537.      {
  1538.       /*
  1539.        * Plot any x/y error bar where the y/x coordinate is in range
  1540.        *  because of bars which reach into plot, even when point
  1541.        *  is outside.
  1542.        */
  1543.       do 
  1544.       {
  1545.            if (start == -1)
  1546.             start = 0;
  1547.            else
  1548.             start = over[i_over++]+1;
  1549.            end = over[i_over];
  1550.  
  1551.            while (end<npts)
  1552.            {
  1553.             if (err_type==XERROR)
  1554.             {
  1555.              /* include some fuzz in comparisons */
  1556.              if ( xy[2*end+1]<(ylow*(1.0-NUM_FUZZ)) || 
  1557.                  xy[2*end+1]>(yhigh*(1.0+NUM_FUZZ))) break;
  1558.              if ( err[2*end]<(xlow*(1.0-NUM_FUZZ)) || 
  1559.                  err[2*end+1]>(xhigh*(1.0+NUM_FUZZ))) break;
  1560.              if ( err[2*end] > xhigh)
  1561.                   err[2*end] = xhigh;
  1562.              if ( err[2*end+1] < xlow)
  1563.                   err[2*end+1] = xlow;
  1564.             }
  1565.             else
  1566.             {
  1567.              if ( xy[2*end]<(xlow*(1.0-NUM_FUZZ)) || 
  1568.                  xy[2*end]>(xhigh*(1.0+NUM_FUZZ))) break;
  1569.              if ( err[2*end]<(ylow*(1.0-NUM_FUZZ)) ||
  1570.                  err[2*end+1]>(yhigh*(1.0+NUM_FUZZ))) break;
  1571.              if ( err[2*end] > yhigh)
  1572.                   err[2*end] = yhigh;
  1573.              if ( err[2*end+1] < ylow)
  1574.                   err[2*end+1] = ylow;
  1575.             }
  1576.             end = over[++i_over];
  1577.            }
  1578.       }
  1579.       while ( (end-start) <= 0 && start<npts );
  1580.             
  1581.       if (start >= npts) continue;
  1582.       
  1583.       if (err_type == YERROR)
  1584.       {
  1585.            PlotSwitch(plot_drvr,drawYError,(&(xy[2*start]),
  1586.                         &(err[2*start]),
  1587.                         end-start));
  1588.       }
  1589.       else
  1590.       {
  1591.            PlotSwitch(plot_drvr,drawXError,(&(xy[2*start]),
  1592.                         &(err[2*start]),
  1593.                         end-start));
  1594.       }
  1595.      }
  1596.      while (rc == 0 && end < npts && start < npts);
  1597.      
  1598.      return rc;
  1599. }
  1600.  
  1601.  
  1602. static int drawColor2D(display disp)
  1603. {
  1604.      int rc=0;
  1605.  
  1606.      if (!init_done)
  1607.      {
  1608.       initPlot( disp );
  1609.       init_done = 1;
  1610.      }
  1611.           
  1612.      rc = disp->drawtype & COLOR;      /* use temporarily */
  1613.      switch (plot_drvr)
  1614.      {
  1615.       NeXTFunc(drawColor2D,(disp->bins.xAxis.nBins,
  1616.                 disp->bins.yAxis.nBins,
  1617.                 &disp->marginRect,
  1618.                 disp->bins.data,
  1619.                 disp->bins.binMin,
  1620.                 disp->bins.binMax,
  1621.                 rc));
  1622.  
  1623.       PSFunc(drawColor2D,(disp->bins.xAxis.nBins,
  1624.                   disp->bins.yAxis.nBins,
  1625.                   &disp->marginRect,
  1626.                   disp->bins.data,
  1627.                   disp->bins.binMin,
  1628.                   disp->bins.binMax,
  1629.                   rc));
  1630.  
  1631.       UPFunc(drawColor2D,(disp));
  1632.       
  1633.       XIVFunc(drawColor2D,(disp->bins.xAxis.nBins,
  1634.                    disp->bins.yAxis.nBins,
  1635.                    disp->bins.binMin,
  1636.                    disp->bins.binMax,
  1637.                    disp->bins.data));
  1638.  
  1639.       X11Func(drawColor2D,(disp->bins.xAxis.nBins,
  1640.                    disp->bins.yAxis.nBins,
  1641.                    disp->bins.binMin,
  1642.                    disp->bins.binMax,
  1643.                    disp->bins.data,
  1644.                    rc));
  1645.  
  1646.      default:
  1647.       rc = -1;
  1648.      }
  1649.      
  1650.      return rc;
  1651. }
  1652.  
  1653.  
  1654. static int drawScatter2D(display disp)
  1655. {
  1656.      int rc;
  1657.      int npts;
  1658.      float *xylist;
  1659.      struct maxs max;
  1660.      
  1661.      npts = getScatData( disp, &xylist, &max );
  1662.      if (npts == 0) return 0;
  1663.      if (npts < 0) 
  1664.      {
  1665.       h_error("h_plot - error getting scatter plot data");
  1666.       return -1;
  1667.      }
  1668.  
  1669.      if (disp->xAxis.flags.autoScale)
  1670.      {
  1671.       disp->xAxis.low = max.xl;
  1672.       disp->xAxis.high = max.xh;
  1673.       h_adjustAxis(&(disp->xAxis.low),&(disp->xAxis.high),
  1674.                0, disp->xAxis.flags.log);
  1675.      }
  1676.      if (disp->yAxis.flags.autoScale)
  1677.      {
  1678.       disp->yAxis.low = max.yl;
  1679.       disp->yAxis.high = max.yh;
  1680.       h_adjustAxis(&(disp->yAxis.low),&(disp->yAxis.high),
  1681.                0, disp->yAxis.flags.log);
  1682.      }
  1683.      
  1684.      if (!init_done)
  1685.      {
  1686.       initPlot( disp );
  1687.       init_done = 1;
  1688.      }
  1689.           
  1690.      PlotSwitch(plot_drvr,drawPoints,(xylist,npts,disp->plotSymbol,
  1691.                       disp->symbolSize));
  1692.      
  1693.      free( xylist );
  1694.      return rc;
  1695. }
  1696.  
  1697.  
  1698. static int getXYData( display disp, float **xy, float **xerr, 
  1699.              float **yerr, int **over, struct maxs *m, int *xmin_pt)
  1700. {
  1701.      int i;
  1702.      float *xp,*yp,*nt;
  1703.      float *last;
  1704.      float xlow, xhigh;
  1705.      float ylow, yhigh;
  1706.      float *xerrorp = NULL, *yerrorp = NULL;
  1707.      float *xerrp, *yerrp;
  1708.      float *xyp;
  1709.      int *overp, isover;
  1710.      int nt_dim = disp->ntuple->ndim;
  1711.      int ylog, xlog;
  1712.      
  1713.  
  1714.      if (disp->binding.x < 0 || disp->binding.y < 0 ||
  1715.      disp->binding.x >= disp->ntuple->ndim ||
  1716.      disp->binding.y >= disp->ntuple->ndim )
  1717.       return -1;
  1718.      
  1719.      m->xl = FLT_MAX;
  1720.      m->xh = -FLT_MAX;
  1721.      m->yl = FLT_MAX;
  1722.      m->yh = -FLT_MAX;
  1723.      
  1724.      ylog = disp->yAxis.flags.log;
  1725.      xlog = disp->xAxis.flags.log;
  1726.      
  1727.      if (disp->xAxis.flags.autoScale)
  1728.      {
  1729.       xlow = -FLT_MAX;
  1730.       xhigh = FLT_MAX;
  1731.      }
  1732.      else
  1733.      {
  1734.       xlow = disp->xAxis.low;
  1735.       xhigh = disp->xAxis.high;
  1736.      }
  1737.      if (disp->yAxis.flags.autoScale)
  1738.      {
  1739.       ylow = -FLT_MAX;
  1740.       yhigh = FLT_MAX;
  1741.      }
  1742.      else
  1743.      {
  1744.       ylow = disp->yAxis.low;
  1745.       yhigh = disp->yAxis.high;
  1746.      }
  1747.      
  1748.      
  1749.      memset((char *)disp->bins.totals, (char)0, sizeof(disp->bins.totals) );
  1750.  
  1751.      if ( (*xy = (float *)malloc( 2*disp->ntuple->ndata*sizeof(float)))
  1752.      == NULL )
  1753.      {
  1754.       h_error("h_plot has run out of memory.");
  1755.       return -1;
  1756.      }
  1757.      if ( disp->drawtype&ERRBAR && disp->binding.xerror >=0 )
  1758.      {
  1759.       if ((*xerr = (float *)malloc( 2*disp->ntuple->ndata*sizeof(float)))
  1760.           == NULL )
  1761.       {
  1762.            free(*xy);
  1763.            h_error("h_plot has run out of memory.");
  1764.            return -1;
  1765.       }
  1766.      }
  1767.      else *xerr = NULL;
  1768.      
  1769.      if ( disp->drawtype&ERRBAR && disp->binding.yerror >= 0 )
  1770.      {
  1771.       if ( (*yerr = (float *)malloc( 2*disp->ntuple->ndata*sizeof(float)))
  1772.           == NULL )
  1773.       {
  1774.            free(xy);
  1775.            free(xerr);
  1776.            h_error("h_plot has run out of memory.");
  1777.            return -1;
  1778.       }
  1779.      }
  1780.      else *yerr = NULL;
  1781.      
  1782.      if ( (*over = (int *)malloc( (disp->ntuple->ndata+1)*sizeof(int)))
  1783.      == NULL )
  1784.      {
  1785.       free(xy);
  1786.       free(xerr);
  1787.       free(yerr);
  1788.       h_error("h_plot has run out of memory.");
  1789.       return -1;
  1790.      }
  1791.      
  1792.      last = &( disp->ntuple->data[INDEX(disp->ntuple->ndata,
  1793.                     0,
  1794.                     disp->ntuple->ndim)] );
  1795.      xp = &(disp->ntuple->data[INDEX(0,disp->binding.x,disp->ntuple->ndim)]);
  1796.      yp = &(disp->ntuple->data[INDEX(0,disp->binding.y,disp->ntuple->ndim)]);
  1797.      if (disp->binding.xerror >=0 )
  1798.       xerrorp = &(disp->ntuple->data[INDEX(0,disp->binding.xerror,
  1799.                            disp->ntuple->ndim)]);
  1800.      if (disp->binding.yerror >=0 )
  1801.       yerrorp = &(disp->ntuple->data[INDEX(0,disp->binding.yerror,
  1802.                            disp->ntuple->ndim)]);
  1803.  
  1804.      nt = &(disp->ntuple->data[INDEX(0,0,disp->ntuple->ndim)]);
  1805.      
  1806.      i = 0;
  1807.      xerrp = *xerr;
  1808.      yerrp = *yerr;
  1809.      xyp = *xy;
  1810.      overp = *over;
  1811.      
  1812.      for ( ; xp<last; 
  1813.       xp += nt_dim, yp += nt_dim, nt += nt_dim,
  1814.       xerrorp += nt_dim, yerrorp += nt_dim )
  1815.      {
  1816.       if (disp->nt_cut!=NULL && doCuts(nt, disp->nt_cut)) continue;
  1817.       
  1818.       isover = 0;
  1819.       
  1820.       if (*xp > xhigh)
  1821.       {
  1822.            if (*yp > yhigh)
  1823.             disp->bins.totals[2][2] += 1.0;
  1824.            else if (*yp < ylow)
  1825.             disp->bins.totals[2][0] += 1.0;
  1826.            else
  1827.             disp->bins.totals[2][1] += 1.0;
  1828.       }
  1829.       else if (*xp < xlow)
  1830.       {
  1831.            if (*yp > yhigh)
  1832.             disp->bins.totals[0][2] += 1.0;
  1833.            else if (*yp < ylow)
  1834.             disp->bins.totals[0][0] += 1.0;
  1835.            else
  1836.             disp->bins.totals[0][1] += 1.0;
  1837.       }
  1838.       else
  1839.       {
  1840.            if (*yp > yhigh)
  1841.             disp->bins.totals[1][2] += 1.0;
  1842.            else if (*yp < ylow)
  1843.             disp->bins.totals[1][0] += 1.0;
  1844.            else
  1845.             disp->bins.totals[1][1] += 1.0;
  1846.       }
  1847.       
  1848.       if (!xlog)
  1849.            *xyp++ = *xp;
  1850.       else
  1851.       {
  1852.            if (*xp > 0.0)
  1853.             *xyp++ = log10(*xp);
  1854.            else
  1855.            {
  1856.             isover = 1;
  1857.             *xyp++ = -FLT_MAX;
  1858.            }
  1859.       }
  1860.       if (*xp > xhigh || *xp < xlow) isover = 1;
  1861.       
  1862.       if (!ylog)
  1863.            *xyp++ = *yp;
  1864.       else
  1865.       {
  1866.            if (*yp > 0.0)
  1867.             *xyp++ = log10(*yp);
  1868.            else
  1869.            {
  1870.             isover = 1;
  1871.             *xyp++ = -FLT_MAX;
  1872.            }
  1873.       }
  1874.       if (*yp > yhigh || *yp < ylow ) isover = 1;
  1875.  
  1876.       if (! isover)
  1877.       {
  1878.            if (*xp > m->xh) m->xh = *xp;
  1879.            if (*xp < m->xl) 
  1880.            {
  1881.             m->xl = *xp;
  1882.             *xmin_pt = i;
  1883.            }
  1884.            
  1885.            if (*yp > m->yh) m->yh = *yp;
  1886.            if (*yp < m->yl) m->yl = *yp;
  1887.       }
  1888.       
  1889.       
  1890.       if (xerrp != NULL) 
  1891.       {
  1892.            *xerrp = *xp + *xerrorp;
  1893.            if (!isover && *xerrp > m->xh) m->xh = *xerrp;
  1894.            if (xlog)
  1895.            {
  1896.             if (*xerrp > 0.0)
  1897.              *xerrp = log10(*xerrp);
  1898.             else 
  1899.             {
  1900.              *xerrp = -FLT_MAX;
  1901.              isover = 1;
  1902.             }
  1903.            }
  1904.            if (*xerrp > xhigh || *xerrp < xlow) isover = 1;
  1905.            xerrp++;
  1906.            
  1907.            *xerrp = *xp - *xerrorp;
  1908.            if (!isover && *xerrp < m->xl &&
  1909.            (!xlog || (xlog && *xerrp>0.0)) ) m->xl = *xerrp;
  1910.            if (xlog) 
  1911.            {
  1912.             if (*xerrp > 0.0)
  1913.              *xerrp = log10(*xerrp);
  1914.             else
  1915.             {
  1916.              *xerrp = -FLT_MAX;
  1917.              isover = 1;
  1918.             }
  1919.            }
  1920.            if (*xerrp > xhigh || *xerrp < xlow) isover = 1;
  1921.            xerrp++;
  1922.       }
  1923.       if (yerrp != NULL) 
  1924.       {
  1925.            *yerrp = *yp + *yerrorp;
  1926.            if (!isover && *yerrp > m->yh) m->yh = *yerrp;
  1927.            if (ylog)
  1928.            {
  1929.             if (*yerrp > 0.0)
  1930.              *yerrp = log10(*yerrp);
  1931.             else
  1932.             {
  1933.              *yerrp = -FLT_MAX;
  1934.              isover = 1;
  1935.             }
  1936.            }
  1937.            if (*yerrp > yhigh || *yerrp < ylow ) isover = 1;
  1938.            yerrp++;
  1939.            
  1940.            *yerrp = *yp - *yerrorp;
  1941.            if (!isover && *yerrp < m->yl &&
  1942.            (!ylog || (ylog && *yerrp > 0.0)) )
  1943.             m->yl = *yerrp;
  1944.            if (ylog)
  1945.            {
  1946.             if (*yerrp > 0.0)
  1947.              *yerrp = log10(*yerrp);
  1948.             else
  1949.             {
  1950.              *yerrp = -FLT_MAX;
  1951.              isover = 1;
  1952.             }
  1953.            }
  1954.            if (*yerrp > yhigh || *yerrp < ylow ) isover = 1;
  1955.            yerrp++;
  1956.       }
  1957.       
  1958.       if (isover)
  1959.       {
  1960.            *overp++ = i;
  1961.            isover = 1;
  1962.       }
  1963.  
  1964.       i++;
  1965.      }
  1966.      
  1967.      /* indicate last item in over */
  1968.      *overp = i;
  1969.      
  1970.      return i;
  1971. }
  1972.  
  1973. static int getHistoData( display disp, float **xy, float **xylego,
  1974.             float **xerr, float **yerr, int **over,
  1975.             struct maxs *m)
  1976. {
  1977.      int i;
  1978.      float binwidth, binside;
  1979.      float *yp;
  1980.      float *last;
  1981.      float *xyp;
  1982.      int *overp;
  1983.      float xlow,xhigh;
  1984.      float ylow, yhigh;
  1985.      float *yerrorp, *xerrp, *yerrp;
  1986.      float *xylegop;
  1987.      float def_bin;
  1988.      int ylog, isover;
  1989.      
  1990.      if (disp->bins.data == NULL) return -1;
  1991.  
  1992.      ylog = disp->yAxis.flags.log;
  1993.      
  1994.      if (disp->xAxis.flags.autoScale)
  1995.      {
  1996.       xlow = -FLT_MAX;
  1997.       xhigh = FLT_MAX;
  1998.      }
  1999.      else
  2000.      {
  2001.       xlow = disp->xAxis.low;
  2002.       xhigh = disp->xAxis.high;
  2003.      }
  2004.      if (disp->yAxis.flags.autoScale)
  2005.      {
  2006.       ylow = -FLT_MAX;
  2007.       yhigh = FLT_MAX;
  2008.      }
  2009.      else
  2010.      {
  2011.       ylow = disp->yAxis.low;
  2012.       yhigh = disp->yAxis.high;
  2013.      }
  2014.      
  2015.      m->xl = FLT_MAX;
  2016.      m->xh = -FLT_MAX;
  2017.      m->yl = FLT_MAX;
  2018.      m->yh = -FLT_MAX;
  2019.      
  2020.      if ( (*xy = (float *)malloc( 2*disp->bins.xAxis.nBins*sizeof(float)))
  2021.      == NULL )
  2022.      {
  2023.       h_error("h_plot has run out of memory.");
  2024.       return -1;
  2025.      }
  2026.      if ( (*xylego = (float *)malloc( 4*(disp->bins.xAxis.nBins+2)*sizeof(float)))
  2027.      == NULL )
  2028.      {
  2029.       free(*xy);
  2030.       h_error("h_plot has run out of memory.");
  2031.       return -1;
  2032.      }
  2033.      if ( disp->drawtype&ERRBAR )
  2034.      {
  2035.       if ( (*xerr = (float *)malloc( 2*disp->bins.xAxis.nBins*sizeof(float)))
  2036.           == NULL )
  2037.       {
  2038.            free(*xy);
  2039.            free(*xylego);
  2040.            h_error("h_plot has run out of memory.");
  2041.            return -1;
  2042.       }
  2043.      }
  2044.      else *xerr = NULL;
  2045.      
  2046.      if ( disp->drawtype&ERRBAR )
  2047.      {
  2048.       if ( (*yerr = (float *)malloc( 2*disp->bins.xAxis.nBins*sizeof(float)))
  2049.           == NULL )
  2050.       {
  2051.            free(*xy);
  2052.            free(*xylego);
  2053.            free(*xerr);
  2054.            h_error("h_plot has run out of memory.");
  2055.            return -1;
  2056.       }
  2057.      }
  2058.      else *yerr = NULL;
  2059.      
  2060.      if ( (*over = (int *)malloc( (disp->bins.xAxis.nBins+1)*sizeof(int)))
  2061.      == NULL )
  2062.      {
  2063.       free(*xy);
  2064.       free(*xylego);
  2065.       free(*xerr);
  2066.       free(*yerr);
  2067.       h_error("h_plot has run out of memory.");
  2068.       return -1;
  2069.      }
  2070.      
  2071.      last = &( disp->bins.data[disp->bins.xAxis.nBins] );
  2072.      yp = disp->bins.data;
  2073.      yerrorp = disp->bins.variance;
  2074.      
  2075.      i = 0;
  2076.      xerrp = *xerr;
  2077.      yerrp = *yerr;
  2078.      xyp = *xy;
  2079.      xylegop = *xylego;
  2080.      overp = *over;
  2081.      binside = disp->xAxis.low;
  2082.      binwidth = (disp->xAxis.high - disp->xAxis.low)/disp->bins.xAxis.nBins;
  2083.  
  2084.      /*
  2085.       * connect the bins to the walls of the plot.
  2086.       * this is only useful if we allow plot axis to be bigger 
  2087.       * than the bin limits.
  2088.       */
  2089.      if (disp->yAxis.low > 0.0) def_bin = disp->yAxis.low;
  2090.      else def_bin = 0.0;
  2091.      if (ylog)
  2092.       if (def_bin > 0.0)
  2093.            def_bin = log10(def_bin);
  2094.       else
  2095.            def_bin = -FLT_MAX;
  2096.      
  2097.      *xylegop++ = disp->xAxis.low;
  2098.      *xylegop++ = def_bin;
  2099.      *xylegop++ = binside;
  2100.      *xylegop++ = def_bin;
  2101.      
  2102.      for ( ; yp<last; yp++, yerrorp++ )
  2103.      {
  2104.       isover = 0;
  2105.       
  2106.       *xyp++ = binside + binwidth/2.0;
  2107.       
  2108.       if (!ylog)
  2109.            *xyp++ = *yp;
  2110.       else
  2111.       {
  2112.            if (*yp > 0.0)
  2113.             *xyp++ = log10(*yp);
  2114.            else
  2115.            {
  2116.             isover = 1;
  2117.             *xyp++ = -FLT_MAX;
  2118.            }
  2119.       }
  2120.       if (*yp > yhigh || *yp < ylow) isover = 1;
  2121.       
  2122.       if (!isover)
  2123.       {
  2124.            if (*yp > m->yh) m->yh = *yp;
  2125.            if (*yp < m->yl && (!ylog || (ylog && *yp>0.0)) )
  2126.             m->yl = *yp;
  2127.       }
  2128.       
  2129.       
  2130.       *xylegop++ = binside;
  2131.       if (xerrp != NULL) *xerrp++ = binside;
  2132.       *xylegop = *yp;
  2133.       if (ylog)
  2134.       {
  2135.            if (*xylegop > 0.0)
  2136.             *xylegop = log10(*xylegop);
  2137.            else
  2138.             *xylegop = -FLT_MAX;
  2139.       }
  2140.       xylegop++;
  2141.       
  2142.       binside += binwidth;
  2143.       *xylegop++ = binside;
  2144.       *xylegop = *(xylegop-2);
  2145.       xylegop++;
  2146.  
  2147.       if (xerrp != NULL) *xerrp++ = binside;
  2148.       
  2149.       if (yerrp != NULL) 
  2150.       {
  2151.            *yerrp = *yp + sqrt(*yerrorp);
  2152.            if (!isover && *yerrp > m->yh) m->yh = *yerrp;
  2153.            if (ylog) 
  2154.            {
  2155.             if (*yerrp > 0.0)
  2156.              *yerrp = log10(*yerrp);
  2157.             else
  2158.             {
  2159.              *yerrp = -FLT_MAX;
  2160.              isover = 1;
  2161.             }
  2162.            }
  2163.            if (*yerrp > yhigh || *yerrp < ylow) isover = 1;
  2164.            yerrp++;
  2165.  
  2166.            *yerrp = *yp - sqrt(*yerrorp);
  2167.            if (!isover && *yerrp < m->yl && 
  2168.            !( ylog && *yerrp<=0.0))
  2169.             m->yl = *yerrp;
  2170.            if (ylog)
  2171.            {
  2172.             if (*yerrp > 0.0)
  2173.              *yerrp = log10(*yerrp);
  2174.             else
  2175.             {
  2176.              *yerrp = -FLT_MAX;
  2177.              isover = 1;
  2178.             }
  2179.            }
  2180.            if (*yerrp > yhigh || *yerrp < ylow) isover = 1;
  2181.            yerrp++;
  2182.       }
  2183.  
  2184.       if (isover)
  2185.       {
  2186.            isover = 1;
  2187.            *overp++ = i;
  2188.       }
  2189.       
  2190.       i++;
  2191.      }
  2192.  
  2193.      /* connect to the walls */
  2194.      *xylegop++ = binside;
  2195.      *xylegop++ = def_bin;
  2196.      *xylegop++ = disp->xAxis.high;
  2197.      *xylegop++ = def_bin;
  2198.      
  2199.      /* indicate last item in over. */
  2200.      *overp = i;
  2201.      
  2202.      return i;
  2203. }
  2204.  
  2205.  
  2206. static int getScatData( display disp, float **xy, struct maxs *m )
  2207. {
  2208.      int i = 0;
  2209.      float *xp,*yp,*nt;
  2210.      float *last;
  2211.      float *xyp;
  2212.      int nt_dim = disp->ntuple->ndim;
  2213.      float xlow, xhigh;
  2214.      float ylow, yhigh;
  2215.      int xlog, ylog;
  2216.      
  2217.  
  2218.      if (disp->binding.x < 0 || disp->binding.y < 0 ||
  2219.      disp->binding.x >= disp->ntuple->ndim ||
  2220.      disp->binding.y >= disp->ntuple->ndim )
  2221.       return -1;
  2222.  
  2223.      xlog = disp->xAxis.flags.log;
  2224.      ylog = disp->yAxis.flags.log;
  2225.      
  2226.      m->xl = FLT_MAX;
  2227.      m->xh = -FLT_MAX;
  2228.      m->yl = FLT_MAX;
  2229.      m->yh = -FLT_MAX;
  2230.      
  2231.      if (disp->xAxis.flags.autoScale)
  2232.      {
  2233.       xlow = -FLT_MAX;
  2234.       xhigh = FLT_MAX;
  2235.      }
  2236.      else
  2237.      {
  2238.       xlow = disp->xAxis.low;
  2239.       xhigh = disp->xAxis.high;
  2240.      }
  2241.      if (disp->yAxis.flags.autoScale)
  2242.      {
  2243.       ylow = -FLT_MAX;
  2244.       yhigh = FLT_MAX;
  2245.      }
  2246.      else
  2247.      {
  2248.       ylow = disp->yAxis.low;
  2249.       yhigh = disp->yAxis.high;
  2250.      }
  2251.      
  2252.      if (xlog && xlow < FLT_MIN) xlow = FLT_MIN;
  2253.      if (ylog && ylow < FLT_MIN) ylow = FLT_MIN;
  2254.      if (xhigh <= xlow) xhigh = xlow + 1.0;
  2255.      if (yhigh <= ylow) yhigh = ylow + 1.0;
  2256.      
  2257.      if ( (*xy = (float *)malloc( 2*disp->ntuple->ndata*sizeof(float)))
  2258.      == NULL )
  2259.      {
  2260.       h_error("h_plot has run out of memory.");
  2261.       return -1;
  2262.      }
  2263.      
  2264.      memset((char *)disp->bins.totals, (char)0, sizeof(disp->bins.totals) );
  2265.  
  2266.      last = &( disp->ntuple->data[INDEX(disp->ntuple->ndata,0,
  2267.                     disp->ntuple->ndim)] );
  2268.      xp = &(disp->ntuple->data[INDEX(0,disp->binding.x,disp->ntuple->ndim)]);
  2269.      yp = &(disp->ntuple->data[INDEX(0,disp->binding.y,disp->ntuple->ndim)]);
  2270.      nt = &(disp->ntuple->data[INDEX(0,0,disp->ntuple->ndim)]);
  2271.      
  2272.      i = 0;
  2273.      xyp = *xy;
  2274.      
  2275.      for ( ; xp<last; 
  2276.       xp += nt_dim, yp += nt_dim, nt += nt_dim )
  2277.      {
  2278.       if (disp->nt_cut!=NULL && doCuts(nt, disp->nt_cut)) continue;
  2279.       
  2280.       if (*xp >= xhigh)
  2281.       {
  2282.            if (*yp > yhigh)
  2283.             disp->bins.totals[2][2] += 1.0;
  2284.            else if (*yp < ylow)
  2285.             disp->bins.totals[2][0] += 1.0;
  2286.            else
  2287.             disp->bins.totals[2][1] += 1.0;
  2288.       }
  2289.       else if (*xp < xlow)
  2290.       {
  2291.            if (*yp >= yhigh)
  2292.             disp->bins.totals[0][2] += 1.0;
  2293.            else if (*yp < ylow)
  2294.             disp->bins.totals[0][0] += 1.0;
  2295.            else
  2296.             disp->bins.totals[0][1] += 1.0;
  2297.       }
  2298.       else
  2299.       {
  2300.            if (*yp > yhigh)
  2301.             disp->bins.totals[1][2] += 1.0;
  2302.            else if (*yp < ylow)
  2303.             disp->bins.totals[1][0] += 1.0;
  2304.            else
  2305.            {
  2306.             disp->bins.totals[1][1] += 1.0;
  2307.             
  2308.             if (!xlog)
  2309.              *xyp++ = *xp;
  2310.             else
  2311.              *xyp++ = log10(*xp);
  2312.             
  2313.             if (!ylog)
  2314.              *xyp++ = *yp;
  2315.             else
  2316.              *xyp++ = log10(*yp);
  2317.             
  2318.             if (*xp > m->xh) m->xh = *xp;
  2319.             if (*xp < m->xl) m->xl = *xp;
  2320.             
  2321.             if (*yp > m->yh) m->yh = *yp;
  2322.             if (*yp < m->yl) m->yl = *yp;
  2323.             
  2324.             i++;
  2325.            }
  2326.       }
  2327.      }
  2328.      
  2329.      return i;
  2330. }
  2331.  
  2332.  
  2333. static int drawLego2D(display disp)
  2334. {
  2335.      int rc;
  2336.      
  2337.      if (!init_done)
  2338.      {
  2339.       initPlot( disp );
  2340.       init_done = 1;
  2341.      }
  2342.           
  2343.      switch (plot_drvr)
  2344.      {
  2345.       NeXTFunc(drawLego2D,( &disp->marginRect ));
  2346.       
  2347.       PSFunc(drawLego2D,( &disp->marginRect ));
  2348.       
  2349.       UPFunc(drawLego2D,( disp ));
  2350.       
  2351.       XIVFunc(drawLego2D,(disp->bins.xAxis.nBins,
  2352.                   disp->bins.yAxis.nBins,
  2353.                   disp->bins.binMin,
  2354.                   disp->bins.binMax,
  2355.                   disp->bins.data));
  2356.       
  2357.       X11Func(drawLego2D,(disp->bins.xAxis.nBins,
  2358.                   disp->bins.yAxis.nBins,
  2359.                   disp->bins.binMin,
  2360.                   disp->bins.binMax,
  2361.                   disp->bins.data));
  2362.       
  2363.       MACFunc(drawLego2D,( &disp->marginRect ));
  2364.  
  2365.      default:
  2366.       rc = -1;
  2367.      }
  2368.      
  2369.      return rc;
  2370. }                 
  2371.  
  2372. int h_shade(display disp, float var1, float var2)
  2373. /*
  2374.  * Shade an area of a plot to indicate area. Make sure not
  2375.  * to outside the bounds of the plot.
  2376.  */
  2377. {
  2378.      int rc;
  2379.      float low, high;
  2380.      
  2381.      if (disp == NULL) return -1;
  2382.  
  2383.      low = (var1 - disp->xAxis.low)/(disp->xAxis.high - disp->xAxis.low);
  2384.      if (low < 0.0) low = 0.0;
  2385.      low = low * disp->marginRect.size.width + disp->marginRect.origin.x;
  2386.  
  2387.      high = (var2 - disp->xAxis.low)/(disp->xAxis.high - disp->xAxis.low);
  2388.      if (high > 1.0) high = 1.0;
  2389.      high = high * disp->marginRect.size.width + disp->marginRect.origin.x;
  2390.      
  2391.      switch (plot_drvr)
  2392.      {
  2393.       NeXTFunc(shade,(low,high,disp->marginRect.origin.y,
  2394.               disp->marginRect.origin.y+
  2395.               disp->marginRect.size.height));
  2396.  
  2397.       PSFunc(shade,(low,high,disp->marginRect.origin.y,
  2398.             disp->marginRect.origin.y+
  2399.             disp->marginRect.size.height));
  2400.       
  2401.       MACFunc(shade,(low,high,disp->marginRect.origin.y,
  2402.               disp->marginRect.origin.y+
  2403.               disp->marginRect.size.height));
  2404.  
  2405.       XIVFunc(shade,(low,high,disp->marginRect.origin.y,
  2406.              disp->marginRect.origin.y+
  2407.              disp->marginRect.size.height));
  2408.       
  2409.         X11Func(shade,(low,high,disp->marginRect.origin.y,
  2410.              disp->marginRect.origin.y+
  2411.              disp->marginRect.size.height));
  2412.       
  2413.      default:
  2414.       rc = -1;
  2415.      }
  2416.      
  2417.      return rc;
  2418. }                 
  2419.  
  2420.  
  2421. typedef struct fp
  2422. {
  2423.      float x,f;
  2424.      struct fp *n;
  2425. } fp;
  2426.  
  2427. static fp *pCache(int n );
  2428. typedef double (*pfun)( double, double *);
  2429.  
  2430. static int plotFunc( display disp, func_id func )
  2431. {
  2432.      int yClip = 0;
  2433.      int i, nCacheUsed;
  2434.      float ylow, yhigh;
  2435.      float maxKink;
  2436.      float delta1, minDelta;
  2437.      float delta2, kink;
  2438.      int isover;
  2439.      
  2440.      fp *list=NULL, *p=NULL, *t;
  2441.      int *over, *overp;
  2442.      float *xy, *xyp;
  2443.      
  2444. #define NSEG_START 20
  2445.  
  2446.      if (disp == NULL || func == NULL) return 0;
  2447.      if (disp->xAxis.high <= disp->xAxis.low) 
  2448.      {
  2449.       h_error("Plotfunc - xAxis.high <= xAxis.low");
  2450.       return 0;
  2451.      }
  2452.      
  2453.      /*
  2454.       * start from the beginning of the cache of point structures.
  2455.       */
  2456.      nCacheUsed = 0;
  2457.      
  2458.      maxKink = 5.0 * 3.141593/180.0;
  2459.      minDelta = 4.0 * (disp->xAxis.high - disp->xAxis.low) /
  2460.       disp->marginRect.size.width;              /* a couple of pixels */
  2461.      
  2462.      if (init_done || !disp->yAxis.flags.autoScale) yClip = 1;
  2463.      ylow = FLT_MAX;
  2464.      yhigh = -FLT_MAX;
  2465.      
  2466.      delta1 = (disp->xAxis.high - disp->xAxis.low)/((float)NSEG_START);
  2467.      for (i=0; i<=NSEG_START; i++)
  2468.      {
  2469.       if (i==0) 
  2470.       {
  2471.            list = pCache(nCacheUsed++);
  2472.            p = list;
  2473.       }
  2474.       else
  2475.       {
  2476.            p->n = pCache(nCacheUsed++);
  2477.            p = p->n;
  2478.       }
  2479.       p->x = disp->xAxis.low + ((float) i) * delta1;
  2480.       p->f = (*(pfun)(func->funcPtr))((double)p->x,
  2481.                       (double *)func->paramBlk);
  2482.       p->n = NULL;
  2483.      }
  2484.      
  2485.      for (p=list; (p->n)->n != NULL; p = p->n )
  2486.      {
  2487.       kink = atan((((p->n)->n)->f - (p->n)->f)/
  2488.               (((p->n)->n)->x - (p->n)->x)) -
  2489.                atan(((p->n)->f - p->f)/((p->n)->x - p->x));
  2490.       delta2 = ((p->n)->n)->x - (p->n)->x;
  2491.       delta1 = (p->n)->x - p->x;
  2492.       while ( fabs(kink) > maxKink && 
  2493.          (delta1 > minDelta || delta2 > minDelta) )
  2494.       {
  2495.            if (delta1 <= delta2)
  2496.            {
  2497.             t = pCache(nCacheUsed++);
  2498.             t->x = (p->n)->x + delta2/2.0;
  2499.             t->f = (float) 
  2500.              (*(pfun)(func->funcPtr))((double)t->x,
  2501.                         (double *)func->paramBlk);
  2502.             t->n = (p->n)->n;
  2503.             (p->n)->n = t;
  2504.            }            
  2505.            if (delta1 >= delta2)
  2506.            {
  2507.             t = pCache(nCacheUsed++);
  2508.             t->x = p->x + delta1/2.0;
  2509.             t->f = (float) 
  2510.              (*(pfun)(func->funcPtr))((double)t->x,
  2511.                         (double *)func->paramBlk);
  2512.             t->n = p->n;
  2513.             p->n = t;
  2514.            }            
  2515.            kink = atan((((p->n)->n)->f - (p->n)->f)/
  2516.                (((p->n)->n)->x - (p->n)->x)) -
  2517.                 atan(((p->n)->f - p->f)/((p->n)->x - p->x));
  2518.            delta2 = ((p->n)->n)->x - (p->n)->x;
  2519.            delta1 = (p->n)->x - p->x;
  2520.       }    
  2521.      }
  2522.      
  2523.      /* 
  2524.       * We now have the complete list of points to plot. Create the
  2525.       *  list of x-y points and overflow flags.
  2526.       */
  2527.      xy = (float *) malloc( 2 * nCacheUsed * sizeof(float) );
  2528.      over = (int *) malloc( (nCacheUsed+1) * sizeof(int) );
  2529.      xyp = xy;
  2530.      overp = over;
  2531.      
  2532.      for (p=list, i=0; i<nCacheUsed; p = p->n, i++ )
  2533.      {
  2534.       isover = 0;
  2535.       
  2536.       if (disp->xAxis.flags.log)
  2537.            if (p->x > 0.0)
  2538.             *xyp++ = p->x;
  2539.            else
  2540.            {
  2541.             isover = 1;
  2542.             *xyp++ = -FLT_MAX;
  2543.            }
  2544.       else
  2545.            *xyp++ = p->x;
  2546.  
  2547.       if (disp->yAxis.flags.log)
  2548.            if (p->f > 0.0)
  2549.             *xyp++ = p->f;
  2550.            else
  2551.            {
  2552.             isover = 1;
  2553.             *xyp++ = -FLT_MAX;
  2554.            }
  2555.       else
  2556.            *xyp++ = p->f;
  2557.       
  2558.       if (isover || 
  2559.           (yClip && (p->f > disp->yAxis.high || p->f < disp->yAxis.low)))
  2560.            *overp++ = i;
  2561.       else
  2562.       {
  2563.            if (p->f > yhigh) yhigh = p->f;
  2564.            if (p->f < ylow && (!disp->yAxis.flags.log || p->f > 0.0))
  2565.             ylow = p->f;
  2566.       }
  2567.      }
  2568.      *overp++ = i;
  2569.      
  2570.      /*
  2571.       * Set scales if it has not been done already.
  2572.       */
  2573.      if (! init_done)
  2574.      {
  2575.       if (disp->yAxis.flags.autoScale)
  2576.       {
  2577.            disp->yAxis.low = ylow;
  2578.            disp->yAxis.high = yhigh;
  2579.            h_adjustAxis(&(disp->yAxis.low), &(disp->yAxis.high),
  2580.                 0, disp->yAxis.flags.log );
  2581.       }
  2582.       initPlot( disp );
  2583.       init_done = 1;
  2584.      }
  2585.      
  2586.      /* 
  2587.       * plot the line, clean up and we're done!
  2588.       */
  2589.      drawLine1D( disp, xy, over, nCacheUsed, 0, func->lineStyle );
  2590.      
  2591.      free(xy);
  2592.      free(over);
  2593.      
  2594.      return 0;
  2595. }
  2596.  
  2597. static fp *pCache(int n )
  2598. {
  2599.      static npoints = 0;
  2600. #define FP_BLK 100
  2601.      static fp *list;
  2602.      
  2603.      if (npoints == 0)
  2604.      {
  2605.       if ( (list = (fp *)malloc( FP_BLK * sizeof(fp) )) == NULL)
  2606.       {
  2607.            h_error("Plotfunc is out of memory");
  2608.            return NULL;
  2609.       }
  2610.       npoints = FP_BLK;
  2611.      }
  2612.      
  2613.      if (n >= npoints)
  2614.      {
  2615.       if ( (list = (fp *)realloc( list, 
  2616.                      (npoints+FP_BLK) * sizeof(fp) )) == NULL)
  2617.       {
  2618.            h_error("Plotfunc is out of memory");
  2619.            return NULL;
  2620.       }
  2621.       npoints += FP_BLK;
  2622.      }
  2623.      
  2624.      return &list[n];
  2625. }
  2626.